package com.delta.rafg.core.log.impl;

import java.util.Properties;

import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueSender;
import javax.jms.Session;

import com.delta.rafg.core.log.ILogQueuer;
import com.delta.rafg.core.log.LogData;
import com.delta.rafg.core.log.LogDataUtil;
import com.delta.rafg.coredata.AObject;

public class LogQueuerJMSTibcoEMS extends AObject implements ILogQueuer {

    private static final long serialVersionUID = 474835396968719424L;
    
    ILogQueuer backupLogQueuer = new LogQueuerDummy();
    
    //These are read from configuration
    static String             queueName              = "DAL.RES.AXIS.Q.LOGDATA";
    static String             qcfName                = "TibcoEMSQueueConnectionFactory";
    static String             queueURL               = "ems-lab2-7232-dv:7232";
    //static String             queueURL               = "10.5.130.110:7222";
    static String             connType               = "JMS";
    static String             queueUser              = "axisuser";
    static String             queuePwd               = "2iFqfpm7";
    
    static ConnectionFactory  queueConnectionFactory = null;
	static MessageProducer 	  msgProducer = null;
	static Connection         queueConnection        = null;
    static Session            queueSession           = null;
    static Queue              queue                  = null; 
    //QueueSender        queueSender            = null;

    private static Properties loggerproperties       = null;
    static {
        loggerproperties = new Properties();
        try {
            loggerproperties.load(LogQueuerJMSTibcoEMS.class
			        .getResourceAsStream("emslogqueuer.properties"));
        }
        catch ( Exception e ) {
        	printStackTrace(e);
        }
    }    
    
    private static boolean    settingsInited            = false;   
    private static int logCount = 0;
    static int QUEUE_LOG_LEVEL = LogData.STATS + LogData.FATAL + LogData.ERROR;
    static{
    	//Load Log Level from VM parameter
    	try{
    		String queueloglevel = System.getProperty("com.delta.rafg.log.queuer.level");
    		QUEUE_LOG_LEVEL = Integer.parseInt(queueloglevel);
    		System.out.print(":: EMS Logger DEBUG :: ");
    		System.out.print("DB Write Log Level set to " + QUEUE_LOG_LEVEL );
    		System.out.println(" from system property com.delta.rafg.log.queuer.level.");
    		
    	}
    	catch(Throwable t){    		
    		System.out.print(":: EMS Logger DEBUG :: ");
    		System.err.print("Could not read system property ");    		
    		System.out.println("com.delta.rafg.log.queuer.level. Using default log level = 7");
    	}
    	//Initialize Queue
    	initEMSLogging();
    }
    
    /* (non-Javadoc)
     * @see com.delta.rafg.core.log.ILogQueuer#queueToLog(com.delta.rafg.core.log.LogData)
     */
    @Override
    public void queueToLog(LogData pLogData) {
		if (pLogData != null) {
			int iSeverity = pLogData.getSeverity();
			if ((QUEUE_LOG_LEVEL & iSeverity) == iSeverity) {
				queueToLog(pLogData, true);
			}
			else{
				backupLogQueuer.queueToLog(pLogData);
			}
		}
    }

    /**
     * Sends pLogData object to the queue either in an ObjectMessage or a BytesMessage.
     * 	based on the bAsBytes parameter.
     * 
     * @param pLogData
     * @param bAsBytes
     */
    public void queueToLog(LogData pLogData, boolean bAsBytes) {   	
        try {        
        	/*
        	logCount++;
        	if(logCount >= 10000)
        	{
        		resetEMSLogging();
        		initEMSLogging();
        		logCount = 0;
        	}
        	*/
            if(bAsBytes){
                BytesMessage btMsg = queueSession.createBytesMessage();
                btMsg.writeBytes(LogDataUtil.get().toByteArray(pLogData));
                msgProducer.send(btMsg);
            }
            else{
                ObjectMessage message = queueSession.createObjectMessage();
                message.setObject(pLogData);                
                msgProducer.send(message);                
            }
        }
        catch ( JMSException e ) {
        	printStackTrace(e);
            dbg(pLogData);
            backupLogQueuer.queueToLog(pLogData);
            initEMSLogging();
        }
        catch ( Throwable e ) {
        	printStackTrace(e);
            dbg(pLogData);
            backupLogQueuer.queueToLog(pLogData);
            initEMSLogging();
        }
    }
    
    
    /**
     * Initializes the Context and looks up Log Writer.
     */
    private static void createFactory() {
    	if( queueConnectionFactory == null)
    		queueConnectionFactory = new com.tibco.tibjms.TibjmsQueueConnectionFactory(queueURL);
    }

    /**
     * Opens the connection to Log Writer.
     * @param queueConnection 
     *
     * @throws JMSException
     */
    private static void createConnection() throws JMSException {        
        loadSettings();
        if(queueConnectionFactory == null)
        	createFactory();
        queueConnection = queueConnectionFactory.createConnection(queueUser,queuePwd);
        queueConnection.start();        
    }

    /**
     * Closes the connection to Log Writer.
     *
     * @throws JMSException
     */
    private void close() throws JMSException {
        if ( queueConnection != null ) {
            queueConnection.stop();
            queueConnection.close();
            queueConnection = null;
        }
    }
    
    public void finalize(){

    }



	public static void loadSettings(){
		if (!settingsInited) {
			queueName 	= getQueueName();
			qcfName 	= getQCFName();
			queueURL 	= getQueueURL();
			queueUser 	= getQueueUser();
			queuePwd 	= getQueuePwd();
			settingsInited = true;
			
			System.out.println("LogQueuerJMSTibcoEMS - One time load of EMS JMS Settings:");
			System.out.println("\tQueue Name: " + queueName);
			System.out.println("\tConnection Factory: " + qcfName);
			System.out.println("\tQueue Server: " + queueURL);
			System.out.println("\tQueue User: " + queueUser);			
		}
		else{
			System.out.println("LogQueuerJMSTibcoEMS - ALREADY LOADED EMS JMS Settings:");
			System.out.println("\tQueue Name: " + queueName);
			System.out.println("\tConnection Factory: " + qcfName);
			System.out.println("\tQueue Server: " + queueURL);
			System.out.println("\tQueue User: " + queueUser);			
		}
	}
	
    private static String myEnvironment = null; 
	private static String getMyEnvirontment(){
		if(myEnvironment == null){
			String environment = System.getProperty("com.delta.rafg.core.config.environment");
			myEnvironment = environment == null ? "" : environment;
		}
		return myEnvironment;
	}

	private static String getProp(String pProp) {
		String strProp = null;
		String env = getMyEnvirontment();
		
		strProp = loggerproperties.getProperty(pProp + "." + env);
		
		if (strProp == null || strProp.trim().length() <= 0)
			strProp = loggerproperties.getProperty(pProp);
			
		return strProp;
	}

	private static String getQueueName(){
		String strProp = getProp("com.delta.rafg.core.log.ems.queuename");
		return strProp == null ? queueName : strProp;
	}
	
	private static String getQCFName(){
		String strProp = getProp("com.delta.rafg.core.log.ems.qcfname");
		return strProp == null ? qcfName : strProp;
	}
	
	private static String getQueueURL(){
		String strProp = getProp("com.delta.rafg.core.log.ems.queueurl");
		return strProp == null ? queueURL : strProp;
	}
    
	private static String getQueueUser(){
		String strProp = getProp("com.delta.rafg.core.log.ems.queueuser");
		return strProp == null ? queueUser : strProp;
	}
    
	private static String getQueuePwd(){
		String strProp = getProp("com.delta.rafg.core.log.ems.queuepwd");
		return strProp == null ? queuePwd : strProp;
	}
    
    /**
     * To test writing of log data to queue
     * 
     * @param argv
     */
    public static void main(String argv[]){
        new LogQueuerJMSTibcoEMS().queueToLog(new LogData("Free text", new Exception()));
    }
    
    private static void dbg(Object pDbg){
		//Do not print if it is not Dev env 
		if("Dev".equalsIgnoreCase(getMyEnvirontment()) 
				|| getMyEnvirontment().trim().length() <=0 ){
			
			System.out.println("pDbg" + pDbg);
		}    	
    }
    
    private static void initEMSLogging()
    {
    	try{
    		System.out.println(":: EMS Logger DEBUG :: Init Sequence Started");
    		System.out.println(":: EMS Logger DEBUG :: 1.Loading EMS Settings");
    		loadSettings();
    		System.out.println(":: EMS Logger DEBUG :: 2.Creating QueueFactory");
    		createFactory();
    		System.out.println(":: EMS Logger DEBUG :: 3.Creating Queue Connection");
    		createConnection();
    		System.out.println(":: EMS Logger DEBUG :: 4.Creating Queue Session");
            queueSession = queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            System.out.println(":: EMS Logger DEBUG :: 5.Creating Queue");
            queue = queueSession.createQueue(queueName);
            System.out.println(":: EMS Logger DEBUG :: 6.Creating Producer");
            msgProducer = queueSession.createProducer(queue);
            System.out.println(":: EMS Logger DEBUG :: Init Sequence Completed");
    	}
    	catch(Throwable t){
    		System.out.println("EMS Logging did not initialize Properly");
    		System.err.print("EMS Logging did not initialize Properly due to : " + t.toString());
    		printStackTrace(t);
    	}
    }
    
    private static void resetEMSLogging()
    {
    	try{
    		System.out.println(":: EMS Logger DEBUG :: Reset Sequence Started");
    		System.out.println(":: EMS Logger DEBUG :: 1.Closing Producer");
    		if(msgProducer != null)
    			msgProducer.close();
    		System.out.println(":: EMS Logger DEBUG :: 2.Closing QueueSession");
    		if(queueSession != null)
    			queueSession.close();
    		System.out.println(":: EMS Logger DEBUG :: 3.Closing QueueConnection");
    		if(queueConnection != null)
    		{
    			queueConnection.stop();
    			queueConnection.close();
    		}           
            System.out.println(":: EMS Logger DEBUG :: Reset Sequence Completed");
    	}
    	catch(Throwable t){
    		System.out.println("EMS Logging did not Reset Properly");
    		System.err.print("EMS Logging did not Reset Properly due to : " + t.getStackTrace()); 
    	}
    }

    private static void printStackTrace(final Throwable e) {
        final StackTraceElement stackTrace = e.getStackTrace()[0];
        String errRes = e.getMessage();
        errRes = errRes == null ? e.toString() : errRes;
        System.err.println(" Error due to " + e.getClass().getSimpleName() + " ("
                + errRes + ")" + "\n\t at " + stackTrace.getClassName() + "."
                + stackTrace.getMethodName() + " ( " + stackTrace.getFileName()
                + ":" + stackTrace.getLineNumber() + ")");
    }    
    
}
